#!/usr/local/bin/python3

import sys
sys.path.append("../src/")

import unittest
import urllib.request
from purest.web.routing import Router, Route


def target1(environ, start_response):
    start_response('200 Ok', [('Content-type', 'text/plain')])
    return ['target1']

def target2(environ, start_response):
    start_response('200 Ok', [('Content-type', 'text/plain')])
    named_params = environ["wsgiorg.routing_args"][1]
    return [named_params["id"]]

def target3(environ, start_response):
    start_response('200 Ok', [('Content-type', 'text/plain')])
    named_params = environ["wsgiorg.routing_args"][1]
    return ["{},{}".format(named_params["city"], named_params["street"]) ]

def target4(environ, start_response):
    start_response('200 Ok', [('Content-type', 'text/plain')])
    return ['target4']


class RouteTest(unittest.TestCase):
       
    def test_simple_match(self):
        route = Route(r"/test/{id}", target2)
        
        matcher = route.match("/test/123")
        
        self.assertEqual("123", matcher.group("id"))

    def test_pattern_match(self):
        route = Route(r"/test/{id: \d+}", target2)
        
        matcher = route.match("/test/123")
        
        self.assertEqual("123", matcher.group("id"))

    def test_failing_pattern_match(self):
        route = Route(r"/test/{id: \d+}", target2)
        
        self.assertFalse(route.match("/test/abc"))
        
    def test_failing_pattern_match_with_root_directory(self):
        route = Route(r"/", target2)
        
        self.assertFalse(route.match("/nix"))        

    def test_render_named_params(self):
        route = Route(r"/{country}/{city}/{street}", target1)
        
        path = route.render(country="germany", city="dresden", 
            street="augsburger strasse")
        
        self.assertEqual("/germany/dresden/augsburger strasse", path)

    def test_render_dictionary(self):
        route = Route(r"/{country}/{city}/{street}", target1)
        params = {"country":"germany", "city":"dresden", 
            "street":"augsburger strasse"}
        
        path = route.render(**params)
        
        self.assertEqual("/germany/dresden/augsburger strasse", path)

class RouterTest(unittest.TestCase):

    router = Router(
        Route(r"/dummy/path/", target1),
        Route(r"/test/{id}", target2),
        Route(r"/location/{city}/{street}", target3),
        Route(r"/path with spaces/", target4)
    )

    def test_routing(self):
        response_status = {"status": ""}
        def start_response(status, headers):
            response_status["status"] = status
        environ = {"PATH_INFO": "/test/123"}
            
        response = RouterTest.router(environ, start_response)
        
        self.assertEqual("123", response[0])
        self.assertEqual("200 Ok", response_status["status"])

    def test_routing_encoded_path(self):
        def start_response(a, b):
            pass
        path = urllib.request.pathname2url("/path with spaces/")
        environ = {"PATH_INFO": path}
        
        response = RouterTest.router(environ, start_response)
        
        content = response[0]
        self.assertEqual("target4", content)
        
    def test_target_not_found(self):
        response_status = {"status": ""}
        def start_response(status, headers):
            response_status["status"] = status
        environ = {"PATH_INFO": "/missing/link"}
        
        response = RouterTest.router(environ, start_response)
        
        self.assertEqual("404 Not Found", response_status["status"])
        
    def test_find_route_by_target(self):
        route = RouterTest.router.get_route_to(target1)
        
        self.assertEqual(route.render(), "/dummy/path/")
        
    def test_raise_error_on_duplicate_target(self):
        def action():
            router = Router(
                Route(r"/dummy/path/", target1),
                Route(r"/test/{id}", target2),
                Route(r"/location/{city}/{street}", target2),
            )
        
        self.assertRaises(AssertionError, action)
        
    def test_raise_error_on_missing_target(self):
        def action():
            RouterTest.router.get_route_to("not existent")
            
        self.assertRaises(KeyError, action)
            
if __name__ == '__main__':
    unittest.main()

